import { RequestHandler } from "express";
import axios from 'axios';
import { getRootDomain } from "../../src/utils";
import { COOKIE_KEY, SEARCH_KEY } from "../../src/utils/constant";
import {UUID} from 'willow-utils/es/buildUtil'
import { initI18n, reloadI18n, setResLanguage } from "../serverUtils/i18nServerUtil";
import { getI18nResource, LANGUAGE } from "../../src/utils/i18nUtil";
const serverConstant = require('../../configs/serverConstant');

// 初始化I18资源，重新加载I18n资源
initI18n()
!serverConstant.devMode && reloadI18n();
// console.log('getI18nResource()',getI18nResource(LANGUAGE.英语));
// 设置默认语言
const DEFAULT_LANGUAGE = LANGUAGE.英语;
// 是否开启屏蔽中文浏览器
const BROWSER_FORBIDDEN = {
	不屏蔽浏览器: 0,
	屏蔽中文浏览器: 1,
};
// 屏蔽IP
const IP_FORBIDDEN = {
	不屏蔽IP: 0 as 0,
	屏蔽所有IP: 1 as 1,
	屏蔽国内IP: 2 as 2,
};
// 站点状态
const SITE_STATE = {
	站点关闭: 0,
	站点开启: 1,
};
// 请求处理
function needCheckState(query): boolean {
	// 更新页面
	if (query[SEARCH_KEY.清除站点缓存] === '1' || query[SEARCH_KEY.清除单页缓存] === '1') return false;
	// 编辑模式
	if (query[SEARCH_KEY.编辑模式] === '1') return false;
	// 预览模式
	if (query[SEARCH_KEY.预览模式] === '1') return false;
	// 调试模式
	if (query[SEARCH_KEY.调试模式] === '1') return false;
	// 非特殊请求
	return true;
}

const temporaryAuthKeySet = new Set<string>();

const initData: RequestHandler = async (req, res, next) => {
  const {realHost, url, path, query, href, isLangDomainSite} = req;
	console.log('realHost',realHost);
	// console.log('req',req);
	// 获取hostname
	const hostname = serverConstant.devMode && realHost && realHost.includes('mydomain.jzt') ? 't12j72.tradechina.com' : req.hostname;
	// 获取根域名, 写 cookie 用
	const rootDomain = getRootDomain(realHost);
	// 检查路径是否合法
	let routePath = '';
	try {
		routePath = decodeURI(path);
	} catch (e) {
		console.error(`[${href}] decodeUri 失败`);
		return res.status(404).end();
	}
	// 检查是否需要更新语言信息
	if (query[SEARCH_KEY.更新I18N数据]) await reloadI18n();
	// 生成访客ID
	const visitorId = req.cookies[COOKIE_KEY.VISITOR_ID] || new Buffer(UUID(), 'utf-8').toString('base64');
	res.cookie(COOKIE_KEY.VISITOR_ID,visitorId,{expires: new Date(Date.now() + 10 * 365.256 * 24 * 3600 * 1000)})
	// 初步检查语言是否合法
	let lang: LANGUAGE;
	const effectiveLangs = Object.values(LANGUAGE);
	// 获取语言
	const [subHost, ...rootDomains] = realHost.split('.');
	const rootHost = rootDomains.join('.');
	const domainLang = (isLangDomainSite ? (subHost === 'www' ? DEFAULT_LANGUAGE : subHost) : null) as LANGUAGE;
	const queryLang = query[SEARCH_KEY.LANGUAGE] as LANGUAGE;
	const cookieLang = req.cookies[COOKIE_KEY.LANGUAGE] as LANGUAGE;
	console.log('rootHost',rootHost);
	console.log('subHost',subHost);
	console.log('domainLang',domainLang);
	console.log('queryLang',queryLang);
	console.log('cookieLang',cookieLang);
	if (isLangDomainSite) {
		lang = domainLang;
		// 首次访问主站, 尝试自动重定向到浏览器对应语言站
		if (subHost === 'www' && !cookieLang) lang = null;
	} else {
		lang = queryLang || cookieLang;
	}
	if (!effectiveLangs.includes(lang)) lang = null;
  // TODO 接口中获取合法的语言列表
	const siteLangList = isLangDomainSite ? [LANGUAGE.英语, LANGUAGE.汉语] : effectiveLangs;
	const meoData: Express.Request['meoData'] = {deployPath: '', lang, routePath};
	// 检查站点状态
	try {
		const checkSiteState = needCheckState(query);
		// 需要检查站点状态说明属于正常访问, 对实时性要求不高, 其他情况使用 1 秒过期的缓存
		const {data} = await axios.post('http://micro.tradechina.com/blade-web-design/front/website/site',{domain: hostname, key: checkSiteState ? 'common' : Date.now() >>> 10})
		// console.log('data---------------------',data);
		meoData.showPrice = data.showPrice !== 0;
		if (checkSiteState) {
			const {browserForbidden, ipForbidden, mouseForbidden, state, accessPwd, closeNotices, defaultLanguage} = data;
			// 检查 浏览器
			if (browserForbidden === BROWSER_FORBIDDEN.屏蔽中文浏览器 && req.header('Accept-Language')?.match(/^zh([-,]|$)/)) {
				console.log(`[${href}] 请求来自中文浏览器, 404`);
				return res.status(404).end();
			}
			// 检查 语言
			if (!lang || !siteLangList.includes(lang)) lang = ((req.header('accept-language') && req.acceptsLanguages(...siteLangList)) || defaultLanguage) as LANGUAGE;
			setResLanguage(res, lang, rootDomain);
			// 语言和域名不一致, 重定向
			if (isLangDomainSite && lang !== domainLang) return res.redirect(`${serverConstant.prodMode ? 'https' : 'http'}://${lang === DEFAULT_LANGUAGE ? 'www' : lang}.${rootHost}${url}`);
			// 检查 站点状态
			if (state === SITE_STATE.站点关闭) {
				const notices = (closeNotices?.find(item => item.lan === lang) || closeNotices?.[0])?.source || '网址维护中';
				console.log(`[${href}] 站点维护中, 404`);
				return res.status(404).send(notices).end();
			}
			// 检查 IP
			if (ipForbidden === IP_FORBIDDEN.屏蔽国内IP || ipForbidden === IP_FORBIDDEN.屏蔽所有IP) {
				const browserPwd = req.cookies[COOKIE_KEY.IP_CHECK_PWD];
				if (browserPwd !== accessPwd) {
					if (ipForbidden === IP_FORBIDDEN.屏蔽所有IP) {
						meoData.needPassword = IP_FORBIDDEN.屏蔽所有IP;
					} else {
						if (temporaryAuthKeySet.has(browserPwd)) {
							// 地区校验通过, 写入 pwd
							res.cookie(COOKIE_KEY.IP_CHECK_PWD, accessPwd, {path: '/', expires: new Date(Date.now() + 10 * 365.256 * 24 * 3600 * 1000)});
						} else {
							// 交由页面检查地区
							const temporaryAuthKey = UUID();
							temporaryAuthKeySet.add(temporaryAuthKey);
							setTimeout(() => temporaryAuthKeySet.delete(temporaryAuthKey), 60e3);
							// 防止客户端时间误差
							res.cookie(COOKIE_KEY.IP_CHECK_AUTH, temporaryAuthKey, {path: '/', expires: new Date(Date.now() + 10 * 60e3)});
							meoData.needPassword = IP_FORBIDDEN.屏蔽国内IP;
						}
					}
				}
			}
			// 写入右键屏蔽参数
			res.cookie(COOKIE_KEY.CONTEXT_MENU_FORBIDDEN, mouseForbidden, {path: '/', expires: new Date(Date.now() + 10 * 365.256 * 24 * 3600 * 1000)});
		} else {
			// 不是普通的访问, 开放右键权限
			res.cookie(COOKIE_KEY.CONTEXT_MENU_FORBIDDEN, 0, {path: '/', expires: new Date(Date.now() + 10 * 365.256 * 24 * 3600 * 1000)});
			// 语言数据异常, 直接设置为默认语言
			if (!lang) {
				if (isLangDomainSite) {
					return res.redirect(`${serverConstant.prodMode ? 'https' : 'http'}://www.${rootHost}${url}`);
				} else {
					lang = DEFAULT_LANGUAGE;
					setResLanguage(res, lang, rootDomain);
				}
			}
		}
	} catch (e) {
		console.error(e);
		res.status(503).end();
	}
	meoData.lang = lang;
  req.meoData = meoData;
	next();
}
export default initData;